[iOS 11] Core MLで焼き鳥を機械学習させてみた
Core ML
Core MLは、学習モデル等をiOS / macOS上で利用する際に、開発者が専門的な知識を必要とせずに扱えるように補助するフレームワークです。WWDC2017で発表された際は、ARKitに並んで現地で反響の大きかった発表でした。
iOSでは、Core ML発表以前から機械学習を取り入れようとはしていました。ただ、そのためにはCIImageを利用した画像処理や、学習モデルへの入出力などのコーディングといった専門的な知識が必要でした。
Core MLの登場で学習モデルを確保できれば、以下の機能を使ってiOS / macOSアプリで機械学習しやすくなります。
- 学習モデルをiOS / macOSアプリで扱える形式に変換する(Core ML model)
- Core ML modelへの入力と出力を補助するフレームワーク
アプリ内に組み込み、学習結果を受け取ることに特化したCore MLを利用することで、以下のメリットが出てきます。
- ネットワークの状態に依存しない
- デバイスのCPUに依存するため、今後のデバイスの進化でより高速に処理ができる
- 結果をサーバーに送らないため、プライバシーを確保できる
上の図のとおり、Core MLはWWDC2017で追加された画像解析用のVisionフレームワークや、拡張されたNatural language processingから入力を受け取り、処理の結果を返すインターフェースを備えています。この記事では、関連するフレームワーク群やツールに関して紹介します。
MLMODEL
MLMODELは学習モデルをXcodeに組み込んで利用できるようにしたファイルの形式です。Xcodeに組み込まれた時点でMLModel
のクラスとしてプログラム上で利用できるようになります。
サポートされているライブラリの学習モデルを後述する変換ツールを利用してMLMODELに変換します。
Appleがサンプルで提供しているMLMODELをアプリに組み込めば、学習モデルを用意しなくても動作の確認を行うことができます。
実際に弊社のSINが試したブログもありますのでこちらも参照していただければと思います。
[iOS 11] Vision.Frameworkで画像の識別を試してみました #WWDC2017
Vision + Core ML
VisionはWWDC2017で発表された、画像解析処理に特化したフレームワークです。
顔検出、オブジェクトの追跡、バーコードの検出などをCIImageなどの画像処理を考慮せずにプログラミングできる強力なインターフェースを備えています。
Visionフレームワークでできることに関しては、 [iOS 11] 画像解析フレームワークVisionで顔認識を試した結果 を参照してください。
Visionフレームワークにはカメラからの映像や、アルバムから取得した写真を学習モデルに入力し、解析の結果を受け取るためのクラスが提供されています。
MLModelを扱いやすいようにしたVNCoreMLModel
クラスや、結果のリクエストを行うVNCoreMLRequest
が上記にあたります。
サンプルとして提供されている MobileNet を利用して試してみました。
MobileNetのMLMODELをXcodeに追加します。
Xcodeに組み込まれたMobileNetはMLModel
というクラスとしてプログラム上で呼び出せるようになります。これをVisionフレームワークで扱えるVNCoreMLModel
に変換します。
// MobileNet(MLModel) を VNCoreMLModelに変換 guard let coreMLModel = try? VNCoreMLModel(for: MobileNet().model) else { return }
変換したVNCoreMLModel
をCore MLに渡し、結果を受け取った後の処理をハンドラーに記述します。
Visionフレームワーク → Core MLへのリクエストはVNCoreMLRequest
が使用します。
let request = VNCoreMLRequest(model: coreMLModel) { request, error in // results は confidence の高い(そのオブジェクトである可能性が高い) // 順番に sort された Array で返ってきます guard let results = request.results as? [VNClassificationObservation] else { return } if let classification = results.first { self.identifierLabel.text = classification.identifier self.confidenceLabel.text = "\(classification.confidence)" } }
リクエスト処理ができましたので、解析したい画像をCIImage
に変換し、画像解析を行うハンドラーを実行します。
captureImage
はカメラのキャプチャー画像をUIImageに変換したものを使用しました(カメラ画像のキャプチャーに関しては今回は割愛します)。
// captureImageはカメラのキャプチャー画像 guard let ciImage = CIImage(image: captureImage) else { return } // VNImageRequestHandlerを作成し、performを実行 let handler = VNImageRequestHandler(ciImage: ciImage, options: [:]) guard (try? handler.perform([request])) != nil else { return }
MLModelさえ準備できれば、少ないプログラムのコード量で画像解析を行うことができました。
Natural language processing
Natural language processingの項目では、Core MLと連携しやすくなった自然言語処理の変更点について記します。
NSLinguisticTagScheme というiOS 5から存在するFoundationのクラスで、iOS 11では以下の品詞分解に特化したenumerateTags
メソッドが追加されました。
- 言語(英語・日本語)判定
- 単語のトークン化
- レンマ化
- 名称分解
試しに、「hello nice to meet Tanaka Takaaki」という言葉を単語のトークン化してみました。
let tagger = NSLinguisticTagger(tagSchemes: [.tokenType], options: 0) // text は入力されたString tagger.string = text let range = NSRange(location: 0, length: text.utf16.count) let options: NSLinguisticTagger.Options = [.omitPunctuation, .omitWhitespace] tagger.enumerateTags(in: range, unit: .word, scheme: .tokenType, options: options) { tag, tokenRange, stop in let token = (text as NSString).substring(with: tokenRange) print("token = \(token)") }
結果は以下のようになりました。
token = hello token = nice token = to token = me token = Tanaka token = Takaaki
今度は名称を取得してみました。
let tagger = NSLinguisticTagger(tagSchemes:[.nameType], options: 0) // text は入力されたString tagger.string = text let range = NSRange(location: 0, length: text.utf16.count) let options: NSLinguisticTagger.Options = [.omitPunctuation, .omitWhitespace, .joinNames] let tags: [NSLinguisticTag] = [.personalName, .placeName, .organizationName] tagger.enumerateTags(in: range, unit: .word, scheme: .nameType, options: options) { tag, tokenRange, stop in if let tag = tag, tags.contains(tag) { let name = (text as NSString).substring(with: tokenRange) print("name = \(name)") } }
結果は以下のようになりました。
name = Tanaka Takaaki
WWDC2017のNatural language processingの項目ではNSLinguisticTagSchemeを利用して、入力された文字列がpositiveな言葉なのか、negativeな言葉なのかを判定するSentiment Analysisのデモが行われていました。
Sentiment Analysisと似たような動作をする SentimentCoreMLDemo を利用して NSLinguisticTagScheme が分解した文字列を、Sentiment Analysisの学習モデルへ渡した結果を表示させるコードを試してみました。
文字列のトークン化はNSLinguisticTagSchemeで行います。
var inputFeatures = [String: Double]() tagger.string = text let range = NSRange(location: 0, length: text.utf16.count) // トークン化 tagger.enumerateTags(in: range, scheme: .nameType, options: options) { _, tokenRange, _, _ in let token = (text as NSString).substring(with: tokenRange).lowercased() // 短い単語はスキップ guard token.count >= 3 else { return } if let value = wordCounts[token] { wordCounts[token] = value + 1.0 } else { wordCounts[token] = 1.0 } }
MLModelのprediction
へトークン化した結果を渡します。
// PipelineのMLModel let model = SentimentPolarity() let output = try model.prediction(input: inputFeatures)
文字列を入力します。
「Hollo world」はpositiveな言葉と判定されました。
では新しいガジェットに関してはどうでしょうか。
negativeな判定となったようです。
どうやらお気に召さなかった…ようですね。
coremltools
各機械学習ライブラリで作成した学習モデルをMLMODELに変換するcoremltools が提供されています。こちらはPython製のライブラリで、オープンソースとして公開されています。
今回はKerasで作成した学習モデルをMLMODELに変換し、Xcodeに組み込んで動作させるところまでやってみました。
EC2にKerasとBackendにTensorFlowが利用できるAMIが公開されていますので、今回は環境構築・学習時間短縮の観点からそちらを利用しました。
p2.xlageなどのGPUが利用できるインスタンスは有料です。利用の際は注意してください。
学習プログラムは CIFAR10のサンプル を利用しました。
あとは学習させたい画像をCIFAR10の対応している32 x 32の形式に切り出しました。
CIFAR10のサンプル を参考に作成した学習プログラムを実行します。
$ python udn_main.py
学習が終了すれば学習モデルが生成されます。
学習モデルからMLMODELへ変換する coremltools をインストールします。
$ sudo pip install coremltools
coremltools
を使用してMLMODEL
へ変換するconvert.py
というPythonのプログラムを作成します。
import coremltools model = coremltools.converters.keras.convert('model.h5', image_input_names = 'data', class_labels = 'labels.txt') model.save('Udon.mlmodel')
convert.py
を実行し、Udon.mlmodel
が作成します。
$ python convert.py
作成したUdon.mlmodel
をVision + Core MLの項目で記した方法と同様にXcodeに組み込み、プログラムから読み込んでみました。
// Udon(MLModel) を VNCoreMLModelに変換 guard let coreMLModel = try? VNCoreMLModel(for: Udon().model) else { return } let request = VNCoreMLRequest(model: coreMLModel) { request, error in // results は confidence の高い(そのオブジェクトである可能性が高い) // 順番に sort された Array で返ってきます guard let results = request.results as? [VNClassificationObservation] else { return } if let classification = results.first { self.identifierLabel.text = classification.identifier self.confidenceLabel.text = "\(classification.confidence)" } } // captureImageはカメラのキャプチャー画像 guard let ciImage = CIImage(image: captureImage) else { return } // VNImageRequestHandlerを作成し、performを実行 let handler = VNImageRequestHandler(ciImage: ciImage, options: [:]) guard (try? handler.perform([request])) != nil else { return }
学習結果は別として、「学習モデル作成」 → 「MLMODELへの変換」 → 「アプリから使用」までを行うことができました。
最後に
自分は今まで機械学習に触れたことがありませんでしたが、coremltoolsの説明で触れたように、「学習モデル作成」 → 「MLMODELへの変換」 → 「アプリから使用」までが簡単に行えるようになりました。
橋渡しを行う coremltools の登場によってアプリケーションエンジニアと機械学習エンジニアの分業がより明確になったことや、学習モデルがプログラムから利用しやすくなったことで、iOSアプリにおける機械学習の機運が高まったのではないかと思いました。
関連リンク
Apple公式情報
- Build more intelligent apps with machine learning
- Introducing Core ML
- Core ML in depth
- coremltools
- Natural Language Processing and your Apps
- Vision
- NSLinguisticTagScheme
公式情報
参考ブログ
- [iOS 11] 画像解析フレームワークVisionで顔認識を試した結果
- [iOS 11] Vision.Frameworkで画像の識別を試してみました #WWDC2017
- [iOS 11] CoreMLで画像の識別を試してみました(Vision.Frameworkを使わないパターン) #WWDC2017
- [iOS 10] 音声認識から得た文章の形態素解析と品詞分解をしてみた
- KerasではじめるDeepLearning
- 著名なディープラーニングフレームワークをサポートするAWS純正AMI:「AWS Deep Learning AMI」
- iOSDC2017でCoreMLの話をしてきました(あるいは法律相談事務所に行ってきた話)
- TensorFlowによるももクロメンバー顔認識(前編)
- Keras + iOS11 CoreML + Vision Framework による、ももクロ顔識別アプリの開発